/**
 *
 * @description: 用户
 * @author: junyong.hong
 * @createTime: 2019/2/21
 * @version: 1.0.0.0
 * @history:
 *    1、
 *    2、
 *
 */
const mongoose = require('mongoose')
const bcrypt = require('bcrypt')
// 加盐
const SALT_WORK_FACTOR = 10
// 最大登录次数
const MAX_LOGIN_ATTEMPTS = 5
// 锁定时间
const LOCK_TIME = 2 * 60 * 60 * 1000

const Schema = mongoose.Schema

const UserSchema = new Schema({
    // 角色: user admin superAdmin
    role: {
        type: String,
        default: 'user'
    },
    // 兼容各个微信应用，小程序或者公众号的微信用户id
    openid: [String],
    unionId: String,
    // 来自哪个渠道关注的
    from: String,
    // 名称
    nickname: String,
    // 地址
    address: String,
    // 省
    province: String,
    // 市
    country: String,
    // 区
    city: String,
    // 性别
    gender: String,
    // 邮箱
    email: {
        // 唯一性，避免重复注册
        unique: true,
        type: String
    },
    // 密码
    password: String,
    // 密码输错次数
    loginAttempts: {
        type: Number,
        required: true,
        default: 0
    },
    // 锁定时间
    lockUntil: Number,
    meta: {
        createdAt: {
            type: Date,
            default: Date.now()
        },
        updatedAt: {
            type: Date,
            default: Date.now()
        }
    }
})

// 虚拟字段（不会真正存入数据库）
UserSchema.virtual('isLocked').get(function () {
    // 锁定的时间大于当前的时间（锁定期内）
    return !!(this.lockUntil && this.lockUntil > Date.now())
})

// 存储之前的中间件
UserSchema.pre('save', function (next) {
    // 如果是新增的
    if (this.isNew) {
        this.meta.createdAt = this.meta.updatedAt = Date.now()
    } else {
        this.meta.updatedAt = Date.now()
    }

    next()
})

UserSchema.pre('save', function (next) {
    let user = this

    if (!user.isModified('password')) {
        return next()
    }

    // 加盐
    bcrypt.genSalt(SALT_WORK_FACTOR, (err, salt) => {
        if (err) {
            return next(err)
        }

        bcrypt.hash(user.password, salt, (error, hash) => {
            if (error) {
                return next(error)
            }

            user.password = hash

            next()
        })
    })
})

// 静态方法
UserSchema.methods = {
    /**
     * 判断用户的登录密码是否正确
     * @param _password
     * @param password
     * @returns {Promise}
     */
    comparePassword: function (_password, password) {
        return new Promise((resolve, reject) => {
            bcrypt.compare(_password, password, function (err, isMatch) {
                if (!err) {
                    resolve(isMatch)
                } else {
                    reject(err)
                }
            })
        })
    },
    /**
     *
     * @param user
     * @returns {Promise}
     */
    incLoginAttempts: function (user) {
        const that = this
        return new Promise((resolve, reject) => {
            // lockUntil 锁定时间
            if (that.lockUntil && that.lockUntil < Date.now()) {
                that.update({
                    $set: {
                        // 密码输错次数
                        loginAttempts: 1
                    },
                    $unset: {
                        // 锁定时间
                        lockUntil: 1
                    }
                }, function (err) {
                    if (!err) {
                        resolve(true)
                    } else {
                        reject(err)
                    }
                })
            } else {
                let updates = {
                    // 密码输错自增1
                    $inc: {
                        loginAttempts: 1
                    }
                }

                // 密码输错大于等于5次
                if (that.loginAttempts + 1 >= MAX_LOGIN_ATTEMPTS || !that.isLocked) {
                    // 锁定2个小时
                    updates.$set = {
                        lockUntil: Date.now() + LOCK_TIME
                    }
                }

                that.update(updates, err => {
                    if (!err) {
                        resolve(true)
                    } else {
                        reject(err)
                    }
                })
            }
        })
    }
}


mongoose.model('User', UserSchema)